﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace CommonLib {
    public class Orientation {
        public static double Nonexistent = 0.0;
        public static double Exterior = 1.0;
        public static double Interior = -1.0;
    }

    public interface Primitive {
        double isIntersect(Ray r, ref double dist);
        Material Material { get; set; }
        bool Light { get; }
        Vector3 getNormal(Vector3 boundryPoint);
    }

    public struct Plane : Primitive {
        public Vector3 position;
        public Vector3 direction;
        public Material material;
        public bool light;

        public Plane(Vector3 pos, Vector3 dir, bool li) {
            this.position = pos;
            this.direction = !dir;
            this.light = li;
            this.material = new Material();
        }
        public double isIntersect(Ray r, ref double dist) {
            double d = (direction & (position - r.position)) / (direction & r.direction);
            if ((0 < d && d < dist) == false)
                return Orientation.Nonexistent;

            dist = d;
            return Orientation.Exterior;
        }
        public Vector3 getNormal(Vector3 bndry) {
            return direction;
        }
        public Material Material {
            get { return material; }
            set { material = value; }
        }
        public bool Light {
            get { return light; }
            set { light = value; }
        }
    }

    public class Sphere : Primitive {
        private Vector3 position;
        private double radius;
        private Material material;
        private bool light;

        public Sphere(Vector3 pos, double rad, bool li) {
            this.position = pos;
            this.radius = rad;
            this.light = li;
            this.material = new Material();
        }
        public double isIntersect(Ray r, ref double dist) {
            // dot = (V, Vo - Po)
            // d = dot^2 - |Vo - Po|^2 + r^2 >= 0
            // t- = -dot - Sqrt(d)
            // t+ = -dot + Sqrt(d)
            // P = tV * Vo
            Vector3 v = r.position - position;
            double dot = r.direction & v;
            double d = dot * dot - (v & v) + radius * radius;
            if ((d > 0) == false)
                return 0.0;

            d = Math.Sqrt(d);
            double tneg = -dot - d;
            double tpos = -dot + d;
            if (0 < tpos) {
                if (0 < tneg && tneg < dist) {
                    dist = tneg;
                    return Orientation.Exterior;
                }
                if (tneg < 0 && tpos < dist) {
                    dist = tpos;
                    return Orientation.Interior;
                }
            }
            
            return Orientation.Nonexistent;
        }
        public Vector3 getNormal(Vector3 bndry) {
            return !(bndry - position);
        }
        public Material Material {
            get { return material; }
            set { material = value; }
        }
        public bool Light {
            get { return light; }
            set { light = value; }
        }
    }
}
